package com.jm.cloud.web.handle;

import com.jm.cloud.web.utils.RequestUtil;
import com.jm.framework.common.exception.BaseResultCodeEnum;
import com.jm.framework.common.exception.BizException;
import com.jm.framework.common.result.BaseResult;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.validation.BindException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.ResponseStatus;

import java.text.MessageFormat;
import java.util.stream.Collectors;

/**
 * tide
 * <p>
 * 全局异常处理
 * <p>
 * author: jiangjianmin
 * <p>
 * create: 2024-08-22 13:40
 **/
@Slf4j
@ControllerAdvice
public class GlobalExceptionHandler {
    /**
     * 处理业务异常，BizException
     */
    @ResponseBody
    @ExceptionHandler(BizException.class)
    public BaseResult<Void> handleException(BizException bizException) {
        log.warn("业务异常 {}", bizException.getMessage());
        return BaseResult.fail(bizException.getCode(), bizException.getMsg());
    }

    /**
     * 参数绑定异常（包含接口参数类型不匹配、@Valid入参校验）
     * <p>
     * 如前端传string，后端用Long接收
     * 或者@Valid注解校验不通过
     */
    @ResponseBody
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    @ExceptionHandler(value = BindException.class)
    public BaseResult<Void> handleException(BindException e) {
        String errorMsg = e.getFieldErrors().stream()
                .map(error -> "[" + error.getField() + "]" + error.getDefaultMessage())
                .collect(Collectors.joining(","));
        log.error("请求入参异常，uri：{}，异常信息：{}", RequestUtil.getRequestInfo(), errorMsg);
        return BaseResult.fail(BaseResultCodeEnum.PARAMS_ERROR, errorMsg);
    }

    public String formatException(Exception e) {
        StringBuilder sb = new StringBuilder();
        sb.append(e.toString());
        for (StackTraceElement ele : e.getStackTrace()) {
            sb.append(MessageFormat.format("  {0}.{1}({2}:{3})  ",
                    ele.getClassName(), ele.getMethodName(), ele.getFileName(), ele.getLineNumber()));
        }
        return sb.toString();
    }
}
